/*
 * @Author: your name
 * @Date: 2021-09-15 09:34:48
 * @LastEditTime: 2022-11-09 08:34:46
 * @LastEditors: zshawk1982
 * @Description: In User Settings Edit
 * @FilePath: \media_system\routes\user.js
 */
const { Sequelize, DataTypes, Transaction } = require("sequelize");
const { User,sequelize } = require("../database/index");
const Router = require("@koa/router");
const jwt = require("jsonwebtoken");
const { formatResponse, filterColumn, resizeAvator } = require("../utils/common");
const moment = require('moment');
const bcrypt = require('bcryptjs')
const path = require('path');
const writeXlsxFile = require('write-excel-file/node')
const router = new Router();
// 配置user路由
/**
 * @swagger
 * /user/add: #接口访问路径(拼接上之前swagger.js中的host)
 *   post: #请求方式
 *     summary: 添加用户  #接口信息
 *     description: 添加用户 #接口描述
 *     tags: [用户] #接口分组
 *     produces:
 *       - application/json
 *     consumes:
 *       - application/json
 *     requestBody:
 *         content:
 *            application/x-www-form-urlencoded:
 *               schema:
 *                  type: object
 *                  required:
 *                  - username
 *                  - realname
 *                  - password
 *                  - gender
 *                  - height
 *                  - weight
 *                  - phone
 *                  - birthDay
 *                  - bmi
 *                  - specialCondition
 *                  - type
 *                  - status
 *                  properties:
 *                     username:          # <!--- form field name
 *                        type: string
 *                        description: 用户名（昵称）
 *                     realname:          # <!--- form field name
 *                        type: string
 *                        description: 真实姓名
 *                     password:          
 *                        type: string
 *                        description: 用户密码
 *                     gender:          
 *                        type: string
 *                        enum: [ "male", "female", "other"]
 *                        description: 性别
 *                     height:          
 *                        type: number
 *                        description: 身高
 *                     weight:          
 *                        type: number
 *                        description: 体重
 *                     phone:          
 *                        type: string
 *                        description: 电话号码
 *                     birthDay:          
 *                        type: string
 *                        description: 出生日期（请务必按照1986-11-22这种格式）
 *                     bmi:          
 *                        type: number
 *                        description: bmi值
 *                     specialCondition:          
 *                        type: integer
 *                        enum: [ "0", "1", "2", "3", "4"]
 *                        description: 糖尿病类型（0正常 1 1型糖尿病 2 2型糖尿病 3混合型糖尿病  4其他特殊类型）
 *                     type:          
 *                        type: "integer"
 *                        enum: [ "0", "1"]
 *                        description: 用户类型（0 管理员 1 普通用户）
 *                     status:          
 *                        type: "integer"
 *                        enum: [ "0", "1"]
 *                        description: 用户状态（0 停用  1 正常）
 *     responses: #返回结果
 *       200:
 *         description: 成功
 */
router.post("/add", async function (ctx, next) {
  let userInfo = ctx.request.body;
  // console.log("userInfo:", userInfo);
  const year = moment().diff(moment(userInfo.birthDay, "YYYY-MM-DD"), 'years');
  let xishu = 0
  if (year > 10) {
    xishu = 70
  } else if (year <= 10 && year >= 7) {
    xishu = 80
  } else if (year < 7 && year >= 3) {
    xishu = 90
  } else {
    xishu = 100
  }
  userInfo.realname = userInfo.realname||"匿名"
  userInfo.totalKcal = 1000 + year * xishu
  userInfo.logoImg = await resizeAvator() //自动随机选择图片作为头像
  const currentUser = await User.create({
    ...userInfo,
  });
  if (currentUser) {
    ctx.body = formatResponse("200", { ...currentUser.get({ plain: true }) }, "success");
  } else {
    ctx.body = formatResponse("500", "", "fail");
  }
});
/**
 * @swagger
 * /user/getUserByName:
 *   get:
 *     security:
 *       - bearerAuth: []
 *     summary: 根据用户名称查询用户
 *     description: 根据用户名称查询用户
 *     tags: [用户]
 *     parameters:
 *       - name: username
 *         in: query #参数存放位置。query是存放到请求头里边
 *         required: true
 *         description: 用户名称
 *         type: string
 *     responses:
 *       200:
 *         description: 成功
 */
router.get("/getUserByName", async function (ctx, next) {
  const Op = Sequelize.Op;
  const { username } = ctx.request.query;
  const user = await User.findOne({
    where: {
      username
    }
  });
  if (user) {
    ctx.body = formatResponse("200", user, "success");
  } else {
    ctx.body = formatResponse("500", { code: 500, message: '用户不纯在' }, "fail");
  }
});
/**
 * @swagger
 * /user/getUserInfo:
 *   get:
 *     security:
 *       - bearerAuth: []
 *     summary: 根据用户ID查询用户信息
 *     description: 根据用户ID查询用户信息
 *     tags: [用户]
 *     parameters:
 *       - name: userId
 *         in: query #参数存放位置。query是存放到请求头里边
 *         required: true
 *         description: 用户id
 *         type: string
 *     responses:
 *       200:
 *         description: 成功
 */
router.get("/getUserInfo", async function (ctx, next) {
  const { userId } = ctx.request.query;
  const currentUser = await User.findByPk(userId);
  // console.log(currentUser, userId);
  if (currentUser) {
    ctx.body = formatResponse("200", { ...currentUser.get({ plain: true }) }, "success");
  } else {
    ctx.body = formatResponse("500", "", "fail");
  }
});



/**
 * @swagger
 * /user/getAllUsers:
 *   get:
 *     security:
 *       - bearerAuth: []
 *     summary: 查询所有用户
 *     description: 查询所有用户
 *     tags: [用户]
 *     responses:
 *       200:
 *         description: 成功
 */
router.get("/getAllUsers", async function (ctx, next) {
  let users = await User.findAll();
  if (users) {
    ctx.body = formatResponse("200", users, "success");
  } else {
    ctx.body = formatResponse("500", "", "fail");
  }
});


/**
 * @swagger
 * /user/getUsersByPageAndCondition:
 *   get:
 *     security:
 *       - bearerAuth: []
 *     summary: 条件分页查询所有用户
 *     description: 条件分页查询所有用户
 *     tags: [用户]
 *     parameters:
 *       - name: username
 *         in: query #参数存放位置。query是存放到请求头里边
 *         description: 用户名称
 *         type: string
 *       - name: gender
 *         in: query #参数存放位置。query是存放到请求头里边
 *         description: 性别（female 女  male男 other其他）
 *         type: string
 *       - name: phone
 *         in: query #参数存放位置。query是存放到请求头里边
 *         description: 电话
 *         type: string
 *       - name: specialCondition
 *         in: query #参数存放位置。query是存放到请求头里边
 *         description: 糖尿病类型（0正常 1 1型糖尿病 2 2型糖尿病 3混合型糖尿病  4其他特殊类型）
 *         type: integer
 *       - name: type
 *         in: query #参数存放位置。query是存放到请求头里边
 *         description: 用户类型（0 管理员 1 普通用户）
 *         type: integer
 *       - name: status
 *         in: query #参数存放位置。query是存放到请求头里边
 *         description: 用户状态（0 停用  1 正常）
 *         type: integer
 *       - name: weight
 *         in: query #参数存放位置。query是存放到请求头里边
 *         description: 体重
 *         schema:
 *          type: array
 *          items:
 *            type: number
 *       - name: currentPage
 *         in: query #参数存放位置。query是存放到请求头里边
 *         required: true
 *         description: 当前第几页
 *         type: string
 *       - name: pageSize
 *         in: query #参数存放位置。query是存放到请求头里边
 *         required: true
 *         description: 一页几条记录
 *         type: string
 *     responses:
 *       200:
 *         description: 成功
 */
router.get("/getUsersByPageAndCondition", async function (ctx, next) {
  const Op = Sequelize.Op;
  const { currentPage, pageSize, username, gender, phone, specialCondition, type, status, weight } = ctx.request.query;
  offset = (currentPage - 1) * pageSize || 0;
  //条件1：用户名称
  //条件2：性别（female 女  male男 other其他）
  //条件3：电话
  //条件4：特殊条件（0正常 1 1型糖尿病 2 2型糖尿病 3混合型糖尿病  4其他特殊类型）
  //条件5：用户类型（0 管理员 1 普通用户）
  //条件6：用户状态（0 停用  1 正常）
  //条件7：体重（多少到多少）
  const condition1 = username ? { username: { [Op.like]: `%${username}%` } } : null;
  const condition2 = gender ? { gender: { [Op.eq]: gender } } : null;
  const condition3 = phone ? { phone: { [Op.eq]: phone } } : null;
  const condition4 = specialCondition ? { specialCondition: { [Op.eq]: specialCondition } } : null;
  const condition5 = type ? { type: { [Op.eq]: type } } : null;
  const condition6 = status ? { status: { [Op.eq]: status } } : null;
  const condition7 = weight ? weight.length > 0 ? { 'weight': { [Op.between]: weight } } : null : null;
  let result = await User.findAndCountAll({
    where: Object.assign({}, condition1, condition2, condition3, condition4, condition5, condition6, condition7),
    order: [['createdAt', 'DESC']],
    offset,
    limit: parseInt(pageSize),
  });
  if (result) {
    ctx.body = formatResponse("200", result, "success");
  } else {
    ctx.body = formatResponse("500", "", "fail");
  }
});

/**
 * @swagger
 * /user/getUserIsExist:
 *   get:
 *     security:
 *       - bearerAuth: []
 *     summary: 根据用户名(昵称)查询普通用户是否存在
 *     description: 根据用户名(昵称)查询普通用户是否存在
 *     tags: [用户]
 *     parameters:
 *       - name: username
 *         in: query #参数存放位置。query是存放到请求头里边
 *         description: 用户名称
 *         type: string
 *     responses:
 *       200:
 *         description: 成功
 */
router.get("/getUserIsExist", async function (ctx, next) {
  const Op = Sequelize.Op;
  const { username} = ctx.request.query;
  let user = await User.findOne(
    {
      where: {
        username,
        type: {
          [Op.eq]: 1
        }
      },
      attributes: ['userId']
    }
  );
  // console.log(111111,user)
  let isExist = false
  if (user) {
    isExist = true
    ctx.body = formatResponse("200", {isExist,message:'该用户已存在'}, "success");
  } else {
    isExist = false
    ctx.body = formatResponse("500", {isExist,message:'该用户不存在'}, "fail");
  }
});

/**
 * @swagger
 * /user/getAdminIsExist:
 *   get:
 *     security:
 *       - bearerAuth: []
 *     summary: 根据用户名(昵称)查询管理员是否存在
 *     description: 根据用户名(昵称)查询管理员是否存在
 *     tags: [用户]
 *     parameters:
 *       - name: username
 *         in: query #参数存放位置。query是存放到请求头里边
 *         description: 用户名称
 *         type: string
 *     responses:
 *       200:
 *         description: 成功
 */
router.get("/getAdminIsExist", async function (ctx, next) {
  const Op = Sequelize.Op;
  const { username} = ctx.request.query;
  let user = await User.findOne(
    {
      where: {
        username,
        type: {
          [Op.eq]: 0
        }
      },
      attributes: ['userId']
    }
  );
  // console.log(111111,user)
  let isExist = false
  if (user) {
    isExist = true
    ctx.body = formatResponse("200", {isExist,message:'该管理员已存在'}, "success");
  } else {
    isExist = false
    ctx.body = formatResponse("500", {isExist,message:'该管理员不存在'}, "fail");
  }
});

/**
 * @swagger
 * /user/login: #接口访问路径(拼接上之前swagger.js中的host)
 *   post: #请求方式
 *     summary: 用户登录/注册  #接口信息
 *     description: 用户未注册自动注册，未登录直接登录 #接口描述
 *     tags: [用户] #接口分组
 *     produces:
 *       - application/json
 *     consumes:
 *       - application/json
 *     requestBody:
 *         content:
 *            application/x-www-form-urlencoded:
 *               schema:
 *                  type: object
 *                  properties:
 *                     username:          # <!--- form field name
 *                        type: string
 *                        description: 用户名（昵称）
 *                     password:          # <!--- form field name
 *                        type: string
 *                        description: 用户密码
 *     responses: #返回结果
 *       200:
 *         description: 成功
 */
router.post("/login", async function (ctx, next) {
  const Op = Sequelize.Op;
  let { password, username } = ctx.request.body;
  const user = await User.findOne(
    {
      where: {
        username,
        type: {
          [Op.eq]: 1
        }
      }
    }
  )
  if (user) {
    //如果用户存在校验用户密码是否一致
    const result = bcrypt.compareSync(password, user.password);
    if (result) {
      //如果密码验证通过
      const accessToken =
        "Bearer " +
        jwt.sign(
          {
            userId: user.userId,
            username: user.username,
          },
          "zshawk1982",
          {
            expiresIn: 3600 * 24 * 7,
          }
        );
      ctx.body = formatResponse("200", { accessToken, user: user.get({ plain: true }), created: false }, "success");
    } else {
      ctx.body = formatResponse("500", { code: 501, message: '用户密码错误' }, "fail");
    }

  } else {
    //如果用户不存在则创建新用户
    let logoImg = await resizeAvator()
    const nuser = await User.create({
      password,
      username,
      realname:'匿名',
      type: 1,
      status: 1,
      totalKcal: 0,
      logoImg
    })
    if (nuser) {
      const accessToken =
        "Bearer " +
        jwt.sign(
          {
            userId: nuser.userId,
            username: nuser.username,
          },
          "zshawk1982",
          {
            expiresIn: 3600 * 24 * 7,
          }
        );
      ctx.body = formatResponse("200", { accessToken, user: nuser.get({ plain: true }), created: true }, "success");
    } else {
      ctx.body = formatResponse("500", { code: 500, message: "用户创建失败" }, "fail");
    }
  }
});

/**
 * @swagger
 * /user/loginByAdmin: #接口访问路径(拼接上之前swagger.js中的host)
 *   post: #请求方式
 *     summary: 管理员登录  #接口信息
 *     description: 管理员登录(只有一个管理员用户，无管理员注册功能) #接口描述
 *     tags: [用户] #接口分组
 *     produces:
 *       - application/json
 *     consumes:
 *       - application/json
 *     requestBody:
 *         content:
 *            application/x-www-form-urlencoded:
 *               schema:
 *                  type: object
 *                  properties:
 *                     username:          # <!--- form field name
 *                        type: string
 *                        description: 用户名
 *                     password:          # <!--- form field name
 *                        type: string
 *                        description: 用户密码

 *     responses: #返回结果
 *       200:
 *         description: 成功
 */
router.post("/loginByAdmin", async function (ctx, next) {
  const Op = Sequelize.Op;
  let { password, username } = ctx.request.body;
  const user = await User.findOne(
    {
      where: {
        username,
        type: {
          [Op.eq]: 0
        }
      }
    }
  )
  if (user) {
    //如果用户存在校验用户密码是否一致
    const result = bcrypt.compareSync(password, user.password);
    // console.log(1111111111,password, user.password,result)
    if (result) {
      //如果密码验证通过
      const accessToken =
        "Bearer " +
        jwt.sign(
          {
            userId: user.userId,
            username: user.username,
          },
          "zshawk1982",
          {
            expiresIn: 3600 * 24 * 7,
          }
        );
      ctx.body = formatResponse("200", { accessToken, user: user.get({ plain: true }) }, "success");
    } else {
      ctx.body = formatResponse("500", { code: 501, message: '用户密码错误' }, "fail");
    }
  } else {
    ctx.body = formatResponse("500", { code: 502, message: '用户不存在' }, "fail");
  }
});

/**
 * @swagger
 * /user/updateUser: #接口访问路径(拼接上之前swagger.js中的host)
 *   post: #请求方式
 *     security:
 *       - bearerAuth: []
 *     summary: 根据用户ID更新用户信息（不能修改头像，头像是注册时自动插入的）  #接口信息
 *     description: 根据用户ID更新用户信息 #接口描述
 *     tags: [用户] #接口分组
 *     produces:
 *       - application/json
 *     consumes:
 *       - application/json
 *     requestBody:
 *         content:
 *            application/x-www-form-urlencoded:
 *               schema:
 *                  type: object
 *                  properties:
 *                     userId:          # <!--- form field name
 *                        type: string
 *                        description: 用户ID
 *                     username:          
 *                        type: string
 *                        description: 用户名(昵称)
 *                     realname:          
 *                        type: string
 *                        description: 真实姓名
 *                     gender:          
 *                        type: string
 *                        enum: [ "male", "female", "other"]
 *                        description: 性别
 *                     height:          
 *                        type: integer
 *                        description: 身高
 *                     weight:          
 *                        type: number
 *                        description: 体重
 *                     phone:          
 *                        type: string
 *                        description: 电话
 *                     birthDay:          
 *                        type: string
 *                        description: 出生日期
 *                     bmi:          
 *                        type: integer
 *                        description: bmi值
 *                     specialCondition:          
 *                        type: integer
 *                        enum: [ "0", "1", "2", "3", "4"]
 *                        description: 糖尿病类型（0正常 1 1型糖尿病 2 2型糖尿病 3混合型糖尿病  4其他特殊类型）
 *                     type:          
 *                        type: "integer"
 *                        enum: [ "0", "1"]
 *                        description: 用户类型（0 管理员 1 普通用户）
 *                     status:          
 *                        type: "integer"
 *                        enum: [ "0", "1"]
 *                        description: 用户状态（0 停用  1 正常）
 *     responses: #返回结果
 *       200:
 *         description: 成功
 */
router.post("/updateUser", async function (ctx, next) {
  let userInfo = ctx.request.body;
  userInfo = filterColumn(userInfo)
  if (userInfo.hasOwnProperty("birthDay")) {
    const year = moment().diff(moment(userInfo.birthDay, "YYYY-MM-DD"), 'years');
    let xishu = 0
    if (year > 10) {
      xishu = 70
    } else if (year <= 10 && year >= 7) {
      xishu = 80
    } else if (year < 7 && year >= 3) {
      xishu = 90
    } else {
      xishu = 100
    }
    userInfo.totalKcal = 1000 + year * xishu
  }
  if (userInfo.hasOwnProperty("realname")) {
    userInfo.realname = userInfo.realname||'匿名'
  }

  try {
    const result =  await sequelize.transaction((t) => {
      // your transactions
      return User.update(
        {
          ...userInfo
        },
        {
          where: {
            userId: userInfo.userId,
          }, transaction: t
        }
      ).then(async (result) => {
        if (result[0] > 0) {
          //更新成功，查询用户
          return User.findOne({
            where:{
              userId:userInfo.userId
            }, transaction: t
          });
        } else {
          //更新成功却找不到用户,回滚更新
          t.rollback()
        }
      }).then((nuserInfo) => {
        // console.log(111111111111, nuserInfo.get({ plain: true }))
        return nuserInfo.get({ plain: true })
      })
    });
    // transaction has been committed. Do something after the commit if required.
    ctx.body = formatResponse("200", result, "success");
  } catch (err) {
    // do something with the err.
    ctx.body = formatResponse("500", err, "fail");
  }
});

/**
 * @swagger
 * /user/updateAdmin: #接口访问路径(拼接上之前swagger.js中的host)
 *   post: #请求方式
 *     security:
 *       - bearerAuth: []
 *     summary: 根据管理员ID更新管理员信息  #接口信息
 *     description: 根据管理员ID更新管理员信息 #接口描述
 *     tags: [用户] #接口分组
 *     produces:
 *       - application/json
 *     consumes:
 *       - application/json
 *     requestBody:
 *         content:
 *            application/x-www-form-urlencoded:
 *               schema:
 *                  type: object
 *                  required:
 *                  - userId
 *                  - username
 *                  - opassword
 *                  properties:
 *                     userId:          # <!--- form field name
 *                        type: string
 *                        description: 用户ID
 *                     username:          
 *                        type: string
 *                        description: 用户名
 *                     opassword:          # <!--- form field name
 *                        type: string
 *                        description: 原始密码
 *                     npassword:          # <!--- form field name
 *                        type: string
 *                        description: 新密码
 *                     phone:          
 *                        type: string
 *                        description: 电话
 *     responses: #返回结果
 *       200:
 *         description: 成功
 */
router.post("/updateAdmin", async function (ctx, next) {
  const Op = Sequelize.Op;
  let adminInfo = ctx.request.body;
  adminInfo = filterColumn(adminInfo)
  const admin = await User.findOne(
    {
      where: {
        userId: adminInfo.userId,
        type: {
          [Op.eq]: 0
        }
      }
    }
  )
  if (bcrypt.compareSync(adminInfo.opassword, admin.password)) {
    //旧密码与数据库的一致才可以更新
    adminInfo.password = adminInfo.npassword
    // console.log(adminInfo.npassword,adminInfo,bcrypt.hashSync(adminInfo.npassword,5))
    const result = await User.update(
      {
        ...adminInfo
      },
      {
        where: {
          userId: adminInfo.userId,
          type: {
            [Op.eq]: 0
          }
        },
      }
    );
    if (result[0] > 0) {
      ctx.body = formatResponse("200", { code: 200, message: '更新成功' }, "success");
    } else {
      ctx.body = formatResponse("500", { code: 501, message: '更新失败' }, "fail");
    }
  } else {
    ctx.body = formatResponse("500", { code: 502, message: '密码不正确' }, "fail");
  }
});



/**
 * @swagger
 * /user/deleteUser:
 *   get:
 *     security:
 *       - bearerAuth: []
 *     summary: 根据用户ID删除用户
 *     description: 根据用户ID删除用户
 *     tags: [用户]
 *     parameters:
 *       - name: userIds
 *         in: query #参数存放位置。query是存放到请求头里边
 *         required: true
 *         description: 用户ID
 *         schema:
 *          type: array
 *          items:
 *            type: string
 *     responses:
 *       200:
 *         description: 成功
 */
router.get("/deleteUser", async function (ctx, next) {
  const { userIds } = ctx.request.query;
  const count = await User.destroy({
    where: {
      userId: userIds
    }
  });
  if (count > 0) {
    ctx.body = formatResponse("200", "", "success");
  } else {
    ctx.body = formatResponse("500", "", "fail");
  }
});


/**
 * @swagger
 * /user/excelExportUsers: #接口访问路径(拼接上之前swagger.js中的host)
 *   post: #请求方式
 *     security:
 *       - bearerAuth: []
 *     summary: excel批量导出所有用户信息  #接口信息
 *     description: excel批量导出所有用户信息 #接口描述
 *     tags: [用户] #接口分组
 *     responses: #返回结果
 *       200:
 *         description: 成功
 */
router.post("/excelExportUsers", async function (ctx, next) {
  const schema = [
    {
      column: '用户名',
      type: String,
      value: s => s.username
    },
    {
      column: '真实姓名',
      type: String,
      value: s => s.realname
    },
    {
      column: '性别',
      type: String,
      value: s => s.gender == 'male' ? '男' : '女'
    },
    {
      column: '身高',
      type: Number,
      value: s => s.height
    },
    {
      column: '体重',
      type: Number,
      value: s => s.weight
    },
    {
      column: '电话号码',
      type: String,
      value: s => s.phone
    },
    {
      column: '出生日期',
      type: String,
      value: s => s.birthDay
    },
    {
      column: 'bmi值',
      type: Number,
      value: s => s.bmi
    },
    {
      column: '总热量',
      type: Number,
      value: s => s.totalKcal
    },
    {
      column: '糖尿病类型',
      type: String,
      value: s => {
        let result = '无'
        if (s.specialCondition == 0) {
          result = '正常'
        } else if (s.specialCondition == 1) {
          result = '1型糖尿病'
        } else if (s.specialCondition == 2) {
          result = '2型糖尿病'
        } else if (s.specialCondition == 3) {
          result = '混合型糖尿病'
        } else if (s.specialCondition == 4) {
          result = '其他特殊类型'
        }
        return result
      }
    }]
  let users = await User.findAll();
  if (users) {
    let res = await writeXlsxFile(users, {
      schema,
      headerStyle: {
        fontWeight: 'bold',
        align: 'center'
      },
      filePath: path.join(__dirname, '../public/exports/user_excel.xlsx')
    })
  } else {
    ctx.body = formatResponse("500", "", "fail");
  }



});

module.exports = router;
